#ifndef _NE_ANIMATION_H_
#define _NE_ANIMATION_H_

#include <animation/NumericAnimationTrack.h>
#include <animation/NodeAnimationTrack.h>
#include <graphics/Skeleton.h>

namespace ne
{
    class NEAPI Animation : public Resource
    {
        public:
            Animation(ResourceManager *pManager,
                      const uint64_t id,
                      const std::string &name,
                      const std::string &fileName,
                      const bool isManual,
                      ManualResourceLoader *pLoader);

            void setLength(const real len);

            real getLength() const;

            NodeAnimationTrackPtr createNodeTrack(const uint16_t handle, Node *node=0);

            size_t getNumNodeTracks() const;

            const NodeAnimationTrackMap& getNodeTrackMap() const;

            NodeAnimationTrackPtr getNodeTrack(const uint16_t handle) const;

            bool hasNodeTrack(const uint16_t handle) const;

            void removeNodeTrack(const uint16_t handle);

            void removeAllNodeTracks();

            void removeAll();

            void apply(const real time, const real weight=1.0, const real scaleU=1.0f);

            void applyToSkeleton(Skeleton *skeleton, const real time, const real weight=1.0, const real scaleU=1.0f);

            void optimise(const bool discardIdentityNodeTracks=true);

            void optimiseNodeTracks(const bool discardIdentityNodeTracks=true);

            virtual ~Animation();

        protected:
            virtual bool loadImplement();

            virtual bool unloadImplement();

            virtual bool downloadImplement();

            virtual size_t _calculateSize() const;

            void _saveNodeTrackToFile(const NodeAnimationTrack &track, FILE *file);

        protected:
            real mLength;
            NodeAnimationTrackMap mNodeTrackMap;
    };

    class NEAPI AnimationPtr : public SharedPtr<Animation>
    {
        public:
            AnimationPtr() : SharedPtr<Animation>() {}
            explicit AnimationPtr(Animation *pAnimation) : SharedPtr<Animation>(pAnimation) {}
            AnimationPtr(const AnimationPtr &pAnimation) : SharedPtr<Animation>(pAnimation) {}

            AnimationPtr(const ResourcePtr &p)
                : SharedPtr<Animation>()
            {
                mpPtr = static_cast<Animation*>(p.ptr());
                mpUseCount = p.getUseCountPtr();
                if (mpUseCount)
                {
                    ++(*mpUseCount);
                }
            }

            AnimationPtr& operator = (const ResourcePtr &p)
            {
                if (mpPtr == static_cast<Animation*>(p.ptr()))
                {
                    return *this;
                }
                AnimationPtr temp(p);
                swap(temp);
                return *this;
            }
    };
}

#endif
